/**
 * Copyright 2002 Cordys R&D B.V. 
 * 
 * This file is part of the Cordys .NET Connector. 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 /**********************************************************************
Find Class Definition .Find class contains methods which can be used 
for search operations
**********************************************************************/

#include "xmlForDotnet.h"
#include "Unmanaged.h"
#include "Managed.h"
#include "Find.h"
#include "Node.h"

using namespace com::eibus::xml::nom;

#pragma managed
Int32 XmlMatchAll(Int32 node, String * pattern)
{
	Byte __pin * pbytes = GetUTF8CharForStr(pattern);
	tHXmlNode result = xmlFindMatch(getXmlNode(node), (tChar*)pbytes);

	ReleasePINPointer(pbytes); 
	return getXmlNodeId(result);
}

Int32 XmlFirstNode(Int32 node,String* pattern)
{
	Byte __pin * pbytes = GetUTF8CharForStr(pattern);
	tHXmlNode result = xmlFindFirst(getXmlNode(node), (tChar*)pbytes);

	ReleasePINPointer(pbytes);
	return getXmlNodeId(result);

}

Int32 XmlFirstMatch(Int32 node, String* pattern)
{
	Byte __pin * pbytes = GetUTF8CharForStr(pattern);
	tHXmlNode result = xmlFindFirstMatch(getXmlNode(node), (tChar*)pbytes);

	ReleasePINPointer(pbytes); 
	return getXmlNodeId(result);
}

Int32 XmlFirstInList(Int32 from, Int32 to, String* pattern)
{
	Byte __pin * pbytes = GetUTF8CharForStr(pattern);
	tHXmlNode result = xmlFindFirstInList(getXmlNode(from), getXmlNode(to),(tChar*)pbytes);

	ReleasePINPointer(pbytes); 
	return getXmlNodeId(result);
}

Int32 XmlFirstMatchInList(Int32 from, Int32 to, String* pattern)
{
	Byte __pin * pbytes = GetUTF8CharForStr(pattern);
	tHXmlNode result = xmlFindFirstMatchInList(getXmlNode(from), getXmlNode(to),(tChar*)pbytes);

	ReleasePINPointer(pbytes); 
	return getXmlNodeId(result);
}

bool XmlListCompare(Int32 from1,Int32 to1, Int32 from2 ,Int32 to2,Int32 depth,Int32 flags)
{
	if (xmlListCmp(getXmlNode(from1), getXmlNode(to1), getXmlNode(from2), getXmlNode(to2), depth, flags))
	{
		return true;
	}
	else
	{
		return false;
	}
}

Int32 XmlMatchInList(Int32 from, Int32 to, String* pattern)
{
	Byte __pin * pbytes = GetUTF8CharForStr(pattern);
	tHXmlNode result = xmlFindMatchInList(getXmlNode(from), getXmlNode(to),(tChar*)pbytes);

	ReleasePINPointer(pbytes); 
	return getXmlNodeId(result);
}


bool XmlIsSameNode(Int32 supposedNode)
{
	if (xmlValidNode(getXmlNode(supposedNode)) == 1)
	{
		return true;
	}
	return false;
}

Int32 XmlFindNodes(Int32 node,String* criteria,Int32 maxFound,Int32* FoundArray)
{

	Byte __pin * pbytes = GetUTF8CharForStr(criteria);
	int found[1];

	tHXmlNode result = xmlFindNodes(getXmlNode(node), (tChar*) pbytes, maxFound, found);

	// If the java integer array is not null, (i.e. the user is interested in
	// the resulting number of nodes found), we must copy it.
	if (FoundArray)
	{
		FoundArray[0] = found[0];

		//Check it out whether its coping properly are not
		/*jint tmp[1];
		env->GetIntArrayRegion(numFound,0,1,tmp);
		tmp[0] = (jint) found[0];
		env->SetIntArrayRegion(numFound,0,1,tmp);*/
	}

	ReleasePINPointer(pbytes); 
	return getXmlNodeId(result);
}

Int32 XmlSSNodes(Int32 node,String* criteria,Int32 maxFound,Int32* FoundArray)
{
	Byte __pin * pbytes = GetUTF8CharForStr(criteria);
	int found[1];

	tHXmlNode result = xmlFindSetOfSiblingNodes(getXmlNode(node), (tChar*) pbytes, maxFound, found);

	// If the java integer array is not null, (i.e. the user is interested in
	// the resulting number of nodes found), we must copy it.
	if (FoundArray)
	{
		FoundArray[0] = found[0];

		//Check it out whether its coping properly are not
		/*jint tmp[1];
		env->GetIntArrayRegion(numFound,0,1,tmp);
		tmp[0] = (jint) found[0];
		env->SetIntArrayRegion(numFound,0,1,tmp);*/
	}

	ReleasePINPointer(pbytes); 
	return getXmlNodeId(result);
}


/** Returns all data of the the first node that matches the pattern. Internally,
 *  this calls Find.match and consequently Node.getData() on each of the resulting nodes. Notice that
 *  Node.getData() will return a concatenation of the String values of all child nodes of type data if
 *  the node on which it is called is of type element.
 *  @param node The node to start searching in.
 *  @param pattern The pattern to match.
 *  @return The node that matches, or 0 if no match was found.
 */
String* Find::Data(Int32 node, String* pattern)[]
{
	Int32  matchResult[] = Match(node,pattern);
	String* matchStrings[] = new String*[matchResult->Length];

	if(matchResult->Length)
	{
		for (Int32 i=0; i<matchResult->Length; i++)
			{
				matchStrings[i] = Node::GetData(matchResult[i]);
			}			
	}
	return matchStrings;
}

/** Retrieves the first node that matches the criteria
    *@param node int reference of the node
    *@param criteria specify name of the node that should be found
*/
Int32 Find::FirstNode(Int32 node, String* pattern)
{
	return XmlFirstNode(node,pattern); 
}

/** Returns the first node that matches the pattern
* @param node The node to start searching in.
* @param pattern The pattern to match.
* @return The node that matches, or 0 if no match was found.
*/
Int32 Find::FirstMatch(Int32 node, String* pattern)
{
	return XmlFirstMatch(node,pattern);
}

/** Returns all data of the the first node that matches the pattern. Internally,
* this calls Find.firstMatch and consequently Node.getData(). Notice that
* Node.getData() will return a concatenation of the String values of all child nodes of type data if
* the node on which it is called is of type element.
* @param node The node to start searching in.
* @param pattern The pattern to match.
* @param defaultValue The default value to return if no matching node was found
* @return The node that matches, or 0 if no match was found.
*/
String* Find::FirstData(Int32 node, String* pattern, String* defaultValue)
{
	return Node::GetData(Find::FirstMatch(node,pattern),defaultValue);  
}

/** Returns the first element child of the first node that matches the pattern. This function
* can be used instead of a pattern ending with 'fChild', since fChild can also return nodes
* of type data.
* @param node The node to start searching in.
* @param pattern The pattern to match.
* @return The first element child of the node that matches, or 0 if no match was found.
*/
Int32 Find::FirstElement(Int32 node, String* pattern)
{
	return Node::GetFirstElement(Find::FirstMatch(node,pattern));  
}

/** Returns the first element children of the nodes that match the pattern. Basically,
* this calles Find.match, and on each of the resulting nodes, Node.getFirstElement is
* called. This function can be used instead of a pattern that ends with 'fChild', since
* 'fChild' may also result in a node of type data.
* @param node The node to start searching in.
* @param pattern The pattern to match.
* @return An array of nodes.
*/
Int32 Find::FirstElements(Int32 node, String* pattern)__gc[]
{
	Int32 result[] = Find::Match(node,pattern);
	Int32 firstElements[] = new Int32 __gc[result->Length];

	for(Int32 index = 0;index<result->Length;index++)
	{
		firstElements[index] = Node::GetFirstElement(result[index]); 
	}
	return firstElements;
}

/** Retrieves the first node in the list of nodes that matches the criteria
    *@param from int reference of the node
    *@param to until which node
    *@param criteria specify name of the node that should be found
*/
Int32 Find::FirstInList(Int32 from, Int32 to, String* pattern)
{
	return XmlFirstInList(from,to,pattern);
}

/** Returns the first node that matches the pattern
* @param from The node to start searching in.
* @param to The last node to search in.
* @param pattern The pattern to match.
* @return The node that matches, or 0 if no match was found.
*/
Int32 Find::FirstMatchInList(Int32 from, Int32 to, String* pattern)
{
	return XmlFirstMatchInList(from,to,pattern);
}


/** Compares two lists of XML nodes for equality
    *@param from1 int reference of the first node
    *@param  to1 int reference of until which node of the first node
    *@param from2 int reference of the second node node
    *@param  to2 int reference of until which node of the second node
    *@param depth dept until which to compare
    *@param flags specify 0 to compare bothe attributes and values of the specified node
    *             Specify 1 to compare attributes and not values
    *             Specify 2 to compare values
*/
bool Find::ListCompare(Int32 from1,Int32 to1, Int32 from2 ,Int32 to2,Int32 depth,Int32 flags)
{
	return XmlListCompare(from1, to1, from2 , to2, depth, flags);
}

/**
* Returns a list of xml nodes that match the pattern, as an int array of handles of the matching nodes.
* @param node The node to start the search in.
* @param pattern The match-pattern
* @return an array of handles to the matching nodes.
*/
Int32 Find::Match(Int32 node, String* pattern)__gc[]
{
	Int32 result = XmlMatchAll(node,pattern);

	if(result == 0)
	{
		return __gc new Int32[0];
	}

	Int32 lastChild = Node::GetLastChildElement(result);
		try
		{	
			Int32 lastIdx = Convert::ToInt32((Node::GetName(lastChild))->Substring(1));
			Int32  intResult __gc[] = new  Int32 __gc[lastIdx+1];

			Int32 i = 0;
			for (Int32 child = Node::GetFirstChildElement(result); child != 0;)
			{
				intResult[i] = Convert::ToInt32(Node::GetData(child,"0"));
				child = Node::GetNextElement(child);
				i++;
			} 
			return intResult;
		}
		catch (FormatException*)
		{
			// Happens only if the matchAll function does not return numbers anymore.
			return  new Int32 __gc[0];
		}
		__finally
		{
			// Make sure memory is cleaned up.
			Node::Delete(result, result);			
		}
}

//Yet to Implement
//Int32 Find::Match(Int32 node, String* pattern,Object* fileHanlder)__gc[]
//{
//}


/** Returns the Node reference in the range of xml nodes in b/w from and to xml 
* nodes that match the pattern. 
* @param from is the node to start the search in.
* @param to is the node to end the search
* @return An XML node containing the search results.
*/
Int32 Find::MatchInList(Int32 from, Int32 to, String* pattern)
{
	return XmlMatchInList(from,to,pattern);
}

/*
 * Checks if the supposed Node is a node or not
 */
bool Find::IsNode(Int32 supposedNode)
{
	return XmlIsSameNode(supposedNode);
}


Int32 Find::Nodes(Int32 node,String* criteria,Int32 maxFound,Int32* FoundArray)
{
	return XmlFindNodes(node,criteria,maxFound,FoundArray);
}


Int32 Find::SetOfSiblingNodes(Int32 node,String* criteria,Int32 maxFound,Int32* FoundArray)
{
	return XmlSSNodes(node,criteria,maxFound,FoundArray);
}
